package com.yungu.swift.admin.utils;

import com.yungu.swift.utils.StringUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * @author : cuixiuyin
 * @date : 2019/8/31
 * @description 文件下载类
 */
public class DownloadUtils {
    /**
     * 文件下载编码
     * 该编码告诉浏览器文件名的编码方式，以防下载中文文件名时有乱码
     */
    private static String ENCODING = "utf-8";


    private static String COMPRESSION_PATH = File.separator + "tmp";

    /**
     * 文件下载
     *
     * @param response
     * @param filePath 文件在服务器上的路径，包含文件名
     */
    public static void download(HttpServletResponse response, String filePath) {
        File file = new File(filePath);
        download(response, file, null, ENCODING);
    }

    /**
     * 文件下载
     *
     * @param response
     * @param filePath 文件在服务器上的路径，包括文件名称
     * @param fileName 文件下载到浏览器的名称，如果不想让浏览器下载的文件名称和服务器上的文件名称一样，请设置该参数
     */
    public static void download(HttpServletResponse response, String filePath, String fileName) {
        File file = new File(filePath);
        download(response, file, fileName, ENCODING);
    }

    /**
     * 文件下载
     *
     * @param response
     * @param filePath 文件在服务器上的路径，包括文件名称
     * @param fileName 文件下载到浏览器的名称，如果不想让浏览器下载的文件名称和服务器上的文件名称一样，请设置该参数
     * @param encoding 文件名称编码
     */
    public static void download(HttpServletResponse response, String filePath, String fileName, String encoding) {
        File file = new File(filePath);
        download(response, file, fileName, encoding);
    }

    /**
     * 文件下载
     *
     * @param response
     * @param file     文件
     */
    public static void download(HttpServletResponse response, File file) {
        download(response, file, null, ENCODING);
    }

    /**
     * 文件下载
     *
     * @param response
     * @param file     文件
     * @param fileName 文件下载到浏览器的名称，如果不想让浏览器下载的文件名称和服务器上的文件名称一样，请设置该参数
     */
    public static void download(HttpServletResponse response, File file, String fileName) {
        download(response, file, fileName, ENCODING);
    }

    /**
     * 文件下载
     *
     * @param response
     * @param file     文件
     * @param fileName 文件下载到浏览器的名称，如果不想让浏览器下载的文件名称和服务器上的文件名称一样，请设置该参数
     * @param encoding 文件名称编码
     */
    public static void download(HttpServletResponse response, File file, String fileName, String encoding) {
        if (file == null || !file.exists() || file.isDirectory()) {
            return;
        }
        // 如果不指定文件下载到浏览器的名称，则使用文件的默认名称
        if (StringUtils.isBlank(fileName)) {
            fileName = file.getName();
        }

        try (InputStream is = new FileInputStream(file)) {
            download(response, is, fileName, encoding);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 文件下载
     *
     * @param response
     * @param is       文件输入流
     * @param fileName 下载的文件名称
     * @throws IOException
     */
    public static void download(HttpServletResponse response, InputStream is, String fileName) {
        download(response, is, fileName, ENCODING);
    }

    /**
     * 文件下载
     *
     * @param response
     * @param is       文件输入流
     * @param fileName 下载的文件名称
     * @param encoding 编码格式
     */
    public static void download(HttpServletResponse response, InputStream is, String fileName, String encoding) {
        if (is == null || StringUtils.isBlank(fileName)) {
            return;
        }
        try (BufferedInputStream bis = new BufferedInputStream(is);
             BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream())) {
            response.setContentType("application/octet-stream;charset=" + encoding);
            response.setCharacterEncoding(encoding);
            response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(fileName, encoding));
            byte[] buffer = new byte[1024];
            int len;
            while ((len = bis.read(buffer)) != -1) {
                bos.write(buffer, 0, len);
            }
            bos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * ZIP 文件下载
     *
     * @param response 输出流
     * @param path     要压缩的文件夹路径
     * @param fileName 压缩文件名
     * @param encoding 编码格式
     */
    public static void zipDownload(HttpServletResponse response, Path path, String fileName, String encoding) {
        if (StringUtils.isEmpty(fileName)) {
            return;
        }
        if (StringUtils.isEmpty(encoding)) {
            encoding = "utf-8";
        }
        String zipName = COMPRESSION_PATH + File.separator + System.currentTimeMillis() + ".zip";
        File zipFile = new File(zipName);
        try {
            if (!zipFile.getParentFile().exists()) {
                zipFile.getParentFile().mkdir();
            }
            if (!zipFile.exists()) {
                zipFile.createNewFile();
            }
            ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFile));
            List<Path> subPaths = Files.walk(path).collect(Collectors.toList());
            // 循环压缩文件
            for (Path subPath : subPaths) {
                File file = subPath.toFile();
                FileInputStream in = new FileInputStream(file);
                // 添加压缩包文件
                out.putNextEntry(new ZipEntry(file.getName()));
                byte[] buffer = new byte[1024];
                int len;
                while ((len = in.read(buffer)) > 0) {
                    out.write(buffer, 0, len);
                }
                // 关闭入口
                out.closeEntry();
                // 关闭文件流
                in.close();
            }
            // 关闭文件流
            out.close();
            // 写出文件到前台
            InputStream ins = new FileInputStream(zipFile);
            //  放到缓冲流里面
            BufferedInputStream bins = new BufferedInputStream(ins);
            //  获取文件输出IO流
            OutputStream outs = response.getOutputStream();
            BufferedOutputStream bouts = new BufferedOutputStream(outs);
            // 设置response内容的类型
            response.setContentType("application/x-download");
            response.setCharacterEncoding(encoding);
            response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(fileName, encoding));
            int bytesRead;
            byte[] buf = new byte[2048];
            // 开始向网络传输文件流
            while ((bytesRead = bins.read(buf, 0, 2048)) > 0) {
                bouts.write(buf, 0, bytesRead);
            }
            bouts.flush();
            ins.close();
            bins.close();
            outs.close();
            bouts.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            zipFile.deleteOnExit();
        }
    }
}
